package cn.lingyangwl.agile.gateway.auth;

import cn.lingyangwl.agile.gateway.exception.InvalidBearerTokenException;
import cn.lingyangwl.agile.gateway.utils.JwtUtils;
import cn.lingyangwl.agile.model.constants.OAuth2Cons;
import cn.lingyangwl.agile.model.module.auth.*;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * 校验 token, 请求需要授权的接口时候会走当前过滤器
 * @author shenguangyang
 */
@Slf4j
@Component
public class MyOpaqueTokenIntrospect {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    public LoginUser introspect(ServerWebExchange exchange, String token) {
        Claims claims = JwtUtils.parseToken(token);
        if (Objects.isNull(claims)) {
            throw new InvalidBearerTokenException(token);
        }

        Object loginId = claims.get(TokenClaimsKeys.LOGIN_ID);
        Object useId = claims.get(TokenClaimsKeys.USER_ID);
        String tokenType = claims.get(TokenClaimsKeys.TOKEN_TYPE, String.class);
        if (OAuth2Cons.TokenType.REFRESH_TOKEN.equalsIgnoreCase(tokenType)) {
            throw new InvalidBearerTokenException("非法令牌");
        }

        String accessToken = String.format(OAuth2Cons.CACHE_TOKEN, OAuth2ParamKeys.ACCESS_TOKEN, loginId);
        if (!Boolean.TRUE.equals(redisTemplate.hasKey(accessToken))) {
            throw new InvalidBearerTokenException(token);
        }

        String cacheKey = String.format(OAuth2Cons.CACHE_USER_DETAILS, useId, loginId);
        Object cacheUserInfo = redisTemplate.opsForValue().get(cacheKey);
        if (Objects.nonNull(cacheUserInfo)) {
            LoginUser loginUser = (LoginUser) cacheUserInfo;

            if (Objects.isNull(loginUser.getTenant())) {
                loginUser.setTenant(new AuthUserTenant());
            }

            loginUser.setIsTenantOwner(loginUser.getTenant().owner());
            return loginUser;
        } else {
            throw new InvalidBearerTokenException(token);
        }
    }
}
